﻿#ifndef FD_CORE_TIME_H
#define FD_CORE_TIME_H
#pragma once

#include <iomanip>
#include <stdio.h>
#include "kernel/event/event.h"
#include <ctime>
#include "kernel/string_def.h"
#include "kernel/Referenced.h"
#include "kernel/stringutil.h"

namespace FD
{
	namespace Kernel
	{
		/** Basic timestamp (seconds from the epoch) */
		typedef ::time_t TimeStamp;

		/** Time span (in seconds) */
		typedef long TimeSpan;

		namespace
		{
			// from RFC 1123, RFC 850

			const char* rfc_wkday[7] = {
				"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
			};

			const char* rfc_weekday[7] = {
				"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"
			};

			const char* rfc_month[12] = {
				"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
			};
		}

		/// <summary>
		/// 时间类
		/// 可以使用该类获得当前系统时间，并提供计时功能
		/// </summary>
		class FD_Kernel_Export Time : public FD::Kernel::CReferenced
		{
		public:
			/// <summary>
			/// 默认构造函数
			/// </summary>
			/// <param name=""></param>
			/// <returns></returns>
			Time();
			/// <summary>
			/// 构造函数
			/// </summary>
			/// <param name="y">年</param>
			/// <param name="mon">月</param>
			/// <param name="d">日</param>
			/// <param name="h">时</param>
			/// <param name="m">分</param>
			/// <param name="s">秒</param>
			/// <param name="ms">毫秒</param>
			/// <returns></returns>
			Time(INT32 y, INT32 mon, INT32 d, INT32 h, INT32 m, INT32 s, INT32 ms);

		public:
			/// <summary>
			/// 析构函数
			/// </summary>
			/// <param name=""></param>
			/// <returns></returns>
			virtual ~Time();
			/// <summary>
			/// 时间是否为空，未初始化
			/// </summary>
			/// <param name=""></param>
			/// <returns>为空返回true，否则返回false</returns>
			bool isNull() const;
			/// <summary>
			/// 时间是否有效
			/// </summary>
			/// <param name=""></param>
			/// <returns>有效返回true，否则返回false</returns>
			bool isValid() const;
			/// <summary>
			/// 获得年份
			/// </summary>
			/// <param name=""></param>
			/// <returns>年份</returns>
			INT32 year() const;
			/// <summary>
			/// 获得月份
			/// </summary>
			/// <param name=""></param>
			/// <returns>月份</returns>
			INT32 month() const;
			/// <summary>
			/// 获得日期
			/// </summary>
			/// <param name=""></param>
			/// <returns>日期</returns>
			INT32 day() const;
			/// <summary>
			/// 获得当天的小时数，24小时制
			/// </summary>
			/// <param name=""></param>
			/// <returns>小时</returns>
			INT32 hour() const;
			/// <summary>
			/// 获得当前小时的分钟数
			/// </summary>
			/// <param name=""></param>
			/// <returns>分钟数</returns>
			INT32 minute() const;
			/// <summary>
			/// 获得当前分钟的秒数
			/// </summary>
			/// <param name=""></param>
			/// <returns>秒数</returns>
			INT32 second() const;
			/// <summary>
			/// 获得当前秒的毫秒数
			/// </summary>
			/// <param name=""></param>
			/// <returns>毫秒数</returns>
			INT32 msec() const;
			/// <summary>
			/// 获得当月的天数
			/// </summary>
			/// <param name="y">年</param>
			/// <param name="mon">月</param>
			/// <returns>天数</returns>
			INT32 daysofmonth(INT32 y, INT32 mon) const;
			/// <summary>
			/// 设置年份
			/// </summary>
			/// <param name="y">年份</param>
			/// <returns>成功返回true，否则返回false</returns>
			bool setYear(INT32 y);
			/// <summary>
			/// 设置月份
			/// </summary>
			/// <param name="mon">月份</param>
			/// <returns>成功返回true，否则返回false</returns>
			bool setMonth(INT32 mon);
			/// <summary>
			/// 设置日期
			/// </summary>
			/// <param name="d">日期</param>
			/// <returns>成功返回true，否则返回false</returns>
			bool setDay(INT32 d);
			/// <summary>
			/// 设置时间
			/// </summary>
			/// <param name="y">年</param>
			/// <param name="mon">月</param>
			/// <param name="d">日</param>
			/// <param name="h">时</param>
			/// <param name="m">分</param>
			/// <param name="s">秒</param>
			/// <param name="ms">毫秒</param>
			/// <returns>成功返回true，否则返回false</returns>
			bool setTime(INT32 y, INT32 mon, INT32 d, INT32 h, INT32 m, INT32 s, INT32 ms);
			/// <summary>
			/// 设置当天的时分秒毫秒
			/// </summary>
			/// <param name="h">时</param>
			/// <param name="m">分</param>
			/// <param name="s">秒</param>
			/// <param name="ms">毫秒</param>
			/// <returns>成功返回true，否则返回false</returns>
			bool setHMS(INT32 h, INT32 m, INT32 s, INT32 ms);
			/// <summary>
			/// 获得本时间到给定时间的时间差，以秒为单位
			/// </summary>
			/// <param name="t">给定时间</param>
			/// <returns>时间差（秒数）</returns>
			INT32 secsTo(const FD::Kernel::Time &t) const;
			/// <summary>
			/// 拨动年
			/// </summary>
			/// <param name="y">年</param>
			/// <param name="onlyy">只修改年为true</param>
			/// <returns>更改后的时间</returns>
			FD::Kernel::Time addYear(INT32 y) const;
			/// <summary>
			/// 拨动月
			/// </summary>
			/// <param name="mon">月数</param>
			/// <param name="onlymon">只修改月时为true</param>
			/// <returns>更改后的时间</returns>
			FD::Kernel::Time addMon(INT32 mon, bool onlymon = false) const;
			/// <summary>
			/// 拨动天数
			/// </summary>
			/// <param name="d">天数</param>
			/// <returns>更改后的时间</returns>
			FD::Kernel::Time addDay(INT32 d) const;
			/// <summary>
			/// 拨动时针
			/// </summary>
			/// <param name="h">小时数</param>
			/// <returns>更改后的时间</returns>
			FD::Kernel::Time addHour(INT32 h) const;
			/// <summary>
			/// 拨动分针
			/// </summary>
			/// <param name="min">分钟数</param>
			/// <returns>更改后的时间</returns>
			FD::Kernel::Time addMin(INT32 min) const;
			/// <summary>
			/// 拨动秒针
			/// </summary>
			/// <param name="secs">秒数</param>
			/// <returns>更改后的时间</returns>
			FD::Kernel::Time addSecs(INT32 secs) const;
			/// <summary>
			/// 拨动毫秒针
			/// </summary>
			/// <param name="ms">毫秒数</param>
			/// ms + m_nMillisecondsOfDay < 2147483647
			/// 2147483647 = 24*MSECS_PER_DAY + 73883647
			/// 故限定 ms <= 23*MSECS_PER_DAY
			/// <returns>更改后的时间</returns>
			FD::Kernel::Time addMSecs(INT32 ms) const;
			/// <summary>
			/// 获得本时间到给定时间的时间差，以毫秒为单位
			/// </summary>
			/// <param name="t">给定时间</param>
			/// <returns>时间差（毫秒数）</returns>
			INT32 msecsTo(const FD::Kernel::Time &t) const;
			/// <summary>
			/// 重载==运算符
			/// </summary>
			/// <param name="other">右操作数</param>
			/// <returns>相等返回true，否则返回false</returns>
			bool operator==(const FD::Kernel::Time &other) const;
			/// <summary>
			/// 重载!=运算符
			/// </summary>
			/// <param name="other">右操作数</param>
			/// <returns>不相等返回true，否则返回false</returns>
			bool operator!=(const FD::Kernel::Time &other) const;
			/// <summary>
			/// 重载<运算符
			/// </summary>
			/// <param name="other">右操作数</param>
			/// <returns>小于返回true，否则返回false</returns>
			bool operator<(const FD::Kernel::Time &other) const;
			/// <summary>
			/// 重载<=运算符
			/// </summary>
			/// <param name="other">右操作数</param>
			/// <returns>小于等于返回true，否则返回false</returns>
			bool operator<=(const FD::Kernel::Time &other) const;
			/// <summary>
			/// 重载>运算符
			/// </summary>
			/// <param name="other">右操作数</param>
			/// <returns>大于返回true，否则返回false</returns>
			bool operator>(const FD::Kernel::Time &other) const;
			/// <summary>
			/// 重载>=运算符
			/// </summary>
			/// <param name="other">右操作数</param>
			/// <returns>大于等于返回true，否则返回false</returns>
			bool operator>=(const FD::Kernel::Time &other) const;
			/// <summary>
			/// 获得当前系统时间
			/// </summary>
			/// <param name=""></param>
			/// <returns>当前系统时间</returns>
			static FD::Kernel::Time currentTime();
			static uint32 getTickCount();
			/// <summary>
			/// 判断给定时间是否有效
			/// </summary>
			/// <param name="y">年</param>
			/// <param name="mon">月</param>
			/// <param name="d">日</param>
			/// <param name="h">时</param>
			/// <param name="m">分</param>
			/// <param name="s">秒</param>
			/// <param name="ms">毫秒</param>
			/// <returns>有效返回true，否则返回false</returns>
			static bool isValid(INT32 y, INT32 mon, INT32 d, INT32 h, INT32 m, INT32 s, INT32 ms);
			/// <summary>
			/// 从当前时间开始计时
			/// </summary>
			/// <param name=""></param>
			/// <returns></returns>
			void start();
			/// <summary>
			/// 返回从开始计时起经过了多少毫秒并重新开始计时
			/// </summary>
			/// <param name=""></param>
			/// <returns>毫秒数</returns>
			INT32 restart();
			/// <summary>
			/// 返回从计时起经过了多少毫秒
			/// </summary>
			/// <param name=""></param>
			/// <returns>毫秒数</returns>
			INT32 elapsed() const;
			/// <summary>
			/// 获得当天经过了多少毫秒
			/// </summary>
			/// <param name=""></param>
			/// <returns>毫秒数</returns>
			uint32 getDs() const;
			/// <summary>
			/// 设置当天已经过的毫秒数
			/// </summary>
			/// <param name="value">毫秒数</param>
			/// <returns></returns>
			void setDs(uint32 value);
			/// <summary>
			/// 重载=运算符
			/// </summary>
			/// <param name="time">右操作数</param>
			/// <returns>本对象</returns>
			FD::Kernel::Time &operator=(const FD::Kernel::Time &time);

			/// <summary>
			/// 当前时间转换成字符串
			/// Y_M_D_H_M_S_MS
			/// </summary>
			/// <param name=""></param>
			/// <returns></returns>
			/// <memo></memo>
			String toString2();

			/// <summary>
			/// 当前时间转换成字符串
			/// Y-M-D H:M:S
			/// </summary>
			/// <param name=""></param>
			/// <returns></returns>
			/// <memo></memo>
			String toString();
			void fromString(const String& formatTimeStr);

			const String asRFC1123() const
			{
				return FD::Kernel::Stringify()
					<< rfc_wkday[_tm.tm_wday] << ", "
					<< std::setfill('0') << std::setw(2) << _tm.tm_mday << ' '
					<< rfc_month[_tm.tm_mon] << ' '
					<< std::setw(4) << (1900 + _tm.tm_year) << ' '
					<< std::setw(2) << _tm.tm_hour << ':'
					<< std::setw(2) << _tm.tm_min << ':'
					<< std::setw(2) << _tm.tm_sec << ' '
					<< "GMT";
			}

			const String asISO8601() const
			{
				return FD::Kernel::Stringify()
					<< std::setw(4) << (_tm.tm_year + 1900) << '-'
					<< std::setfill('0') << std::setw(2) << (_tm.tm_mon + 1) << '-'
					<< std::setfill('0') << std::setw(2) << (_tm.tm_mday)
					<< 'T'
					<< std::setfill('0') << std::setw(2) << _tm.tm_hour << ':'
					<< std::setfill('0') << std::setw(2) << _tm.tm_min << ':'
					<< std::setfill('0') << std::setw(2) << _tm.tm_sec
					<< 'Z';
			}

			const String asCompactISO8601() const
			{
				return FD::Kernel::Stringify()
					<< std::setw(4) << (_tm.tm_year + 1900)
					<< std::setfill('0') << std::setw(2) << (_tm.tm_mon + 1)
					<< std::setfill('0') << std::setw(2) << (_tm.tm_mday)
					<< 'T'
					<< std::setfill('0') << std::setw(2) << _tm.tm_hour
					<< std::setfill('0') << std::setw(2) << _tm.tm_min
					<< std::setfill('0') << std::setw(2) << _tm.tm_sec
					<< 'Z';
			}

			TimeStamp   asTimeStamp() const { return _time_t; }
		private:
			INT32 m_nYear;
			INT32 m_nMonth;
			INT32 m_nDay;
			INT32 m_nMillisecondsOfDay;
			uint32 m_nTickCount;
			::time_t timegm(const ::tm* tm) const;

			 protected:
				 ::tm     _tm;
				 ::time_t _time_t;
		};
	}
}

#endif

